<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at
   
         http://www.apache.org/licenses/LICENSE-2.0
   
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta name="generator"
          content="HTML Tidy for Windows (vers 1st July 2003), see www.w3.org"/>
    <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"/>
    <link rel="stylesheet" type="text/css" href="base.css"/>

    <title>A Walking Tour of the Struts MailReader Demonstration
        Application</title>
</head>

<body>
<blockquote>
<h2>A Walking Tour of the Struts MailReader Demonstration Application</h2>

<p>
    <i>
        This article is meant to introduce a new user to Struts by "walking
        through" an
        application.
        See the <a href="http://struts.apache.org/">Struts Users Guide and
        Strut's API</a>
        for more documentation.
    </i>
</p>

<p>
    <i>
        The MailReader application is based on the 1.3.0 build of Struts.
        To follow along, you should install the MailReader application on your
        own
        development workstation (e.g. localhost).
    </i>
</p>

<p>
    <i>
        This article assumes the reader has a basic understanding of the Java
        language,
        JavaBeans, web applications, and JavaServer Pages. For background on
        these
        technologies, see the
        <a href="http://struts.apache.org/struts-action/userGuide/preface.html">
            Preface to the Struts User Guide</a>.
    </i>
</p>

<hr/>

<ul>
    <li>
        <a href="#index.jsp">index.jsp</a>

        <ul>
            <li><a href="#web.xml">web.xml and
                ApplicationResources.properties</a></li>

            <li><a href="#DatabaseServlet.java">DatabaseServlet.java</a></li>
        </ul>
    </li>

    <li>
        <a href="#Logon.jsp">Logon.jsp</a>

        <ul>
            <li><a href="#struts-config.xml">struts-config.xml</a></li>

            <li><a href="#LogonForm">LogonForm</a></li>

            <li><a href="#BaseForm">BaseForm</a></li>

            <li><a href="#LogonAction.java">LogonAction.java</a></li>

            <li><a href="#struts-config.xml/2">struts-config.xml 2</a></li>
        </ul>
    </li>

    <li>
        <a href="#MainMenu.jsp">MainMenu.jsp</a>

        <ul>
            <li><a href=""></a></li>
        </ul>
    </li>

    <li>
        <a href="#MainMenu.jsp">EditRegistration.do</a>
    <ul>
        <li><a href="#RegistrationAction.java">RegistrationAction.java</a>
        </li>
    </ul>
    <li>
        <a href="#Registeration.jsp">Registration.jsp</a>

        <ul>
            <li><a href="#RegistrationForm">RegistrationForm</a></li>

            <li><a href="#RegistrationAction.java">RegistrationAction.java</a>
            </li>

            <li><a href="#Edit-SubscriptionAction.java">SubscriptionAction.java</a>
            </li>
        </ul>
    </li>

    <li>
        <a href="#Subcription.jsp">Subscription.jsp</a>

        <ul>
            <li><a href="#SubscriptionForm">SubscriptionForm</a></li>

            <li><a href="#Save-SubscriptionAction.java">SubscriptionAction</a>
            </li>
        </ul>
    </li>

    <li><a href="#Summary">Summary</a></li>
</ul>
<hr/>

<p>
    The Struts App subproject includes four applications: struts-blank,
    struts-cookbook, struts-examples, and
    struts-mailreader.
    This document walks through struts-mailreader, also known as the
    "MailReader Demonstration Application".
</p>

<p>
    The premise of the MailReader is that it is the first iteration of a
    portal application.
    This version allows users to register themselves and maintain a set of
    accounts with various mail servers.
    If completed, the application would let users read mail from their
    accounts.
</p>

<p>
    The MailReader application demonstrates registering with an application,
    logging into an application,
    maintaining a master record, and maintaining child records.
    This document walks through the constructs needed to do these things,
    including the server pages, Java classes,
    and configuration elements.
</p>

<p>
    For more about the MailReader, including alternate implementations and a
    set of formal Use Cases,
    please visit the <a href="http://strutsuniversity.org/MailReader">
    Struts University MailReader site</a>.
</p>

<hr/>
<blockquote>
    <p><font class="hint">
        <strong>JAAS</strong> -
        Note that for compatibility and ease of deployment, the MailReader
        uses "application-based" authorization.
        However, use of the standard Java Authentication and Authorization
        Service (JAAS) is recommended for most
        applications.
        (See the <a
            href="http://struts.apache.org/struts-action/userGuide/preface.html">
        Preface to the Struts Action User Guide</a> for more about
        authentification technologies.)
    </font></p>
</blockquote>
<hr/>

<p>
    The walkthrough starts with how the initial welcome page is displayed, and
    then steps through logging in,
    adding and editing subscriptions, and creating a new registration.
</p>

<h3><a name="howdy" id="howdy">Howdy</a></h3>

<p>
    A web application, like any other web site, can specify a list of welcome
    pages.
    When you open a web application without specifying a particular page, a
    welcome page is used by default.
</p>

<h4><a name="web.xml" id="web.xml">web.xml</a></h4>

<p>
    When a web application loads,
    the container reads and parses the "Web Application Deployment
    Descriptor", or web.xml file.
    The Struts Action Framework plugs into a web application via a controller
    servlet.
    Like any servlet, the Action servlet is deployed via the web.xml.
</p>

<hr/>
<h5>web.xml - The Web Application Deployment Descriptor</h5>
<pre><code>&lt;?xml version="1.0" encoding="ISO-8859-1"?>

    &lt;!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

    &lt;web-app>
    &lt;display-name>Struts MailReader Application&lt;/display-name>

    &lt;!-- Action Servlet Configuration -->
    &lt;servlet>
    &lt;servlet-name>action&lt;/servlet-name>
    &lt;servlet-class>org.apache.struts.action.ActionServlet&lt;/servlet-class>
    &lt;init-param>
    &lt;param-name>config&lt;/param-name>
    &lt;param-value>/WEB-INF/struts-config.xml&lt;/param-value>
    &lt;/init-param>
    &lt;load-on-startup>1&lt;/load-on-startup>
    &lt;/servlet>

    &lt;!-- Servlet Mapping -->
    &lt;servlet-mapping>
    &lt;servlet-name>action&lt;/servlet-name>
    &lt;url-pattern>*.do&lt;/url-pattern>
    &lt;/servlet-mapping>

    &lt;!-- <strong>The Welcome File List</strong> -->
    &lt;welcome-file-list>
    &lt;welcome-file>index.jsp&lt;/welcome-file>
    &lt;/welcome-file-list>

    &lt;!-- The default error page -->
    &lt;error-page>
    &lt;exception-type>java.lang.Exception&lt;/exception-type>
    &lt;location>/Error.jsp&lt;/location>
    &lt;/error-page>

    &lt;/web-app></code></pre>
<hr/>

<p>
    Among other things,
    the web.xml specifies the "Welcome File List" for an application.
    When a web address refers to a directory rather than an individual file,
    the container consults the Welcome File List for the name of a page to
    open by default.
</p>

<p>
    Albeit, most Struts applications do not refer to physical pages,
    but to "virtual pages" called <i>actions</i>.
    The actions are listed in a configuration file.
    Actions contain code that we want to be run before a page is displayed.
    An accepted practice in the Struts Action community is to never link
    directly to server pages,
    but only to Struts actions.
    By linking to actions, developers can "rewire" an application without
    editing the server pages.
</p>

<hr/>
<h5>Best Practice:</h5>
<blockquote>
    <p><font class="hint">"Link actions not pages."</font></p>
</blockquote>
<hr/>

<p>
    Unless you are using Java 1.5, actions cannot be specified as a welcome
    page.
    So, in the case of a welcome page,
    how do we follow the Struts best practice of navigating through actions
    rather than pages?
</p>

<p>
    One solution is to use a server page to "bootstrap" a Struts action.
    A Java web application recognizes the idea of "forwarding" from one page
    to another page (or action).
    We can register the usual "index.jsp" as the welcome page and have it
    forward to a "Welcome" action.
</p>

<hr/>
<h5>MailReader's index.jsp</h5>
<pre><code>&lt;%@ taglib uri="http://struts.apache.org/tags-logic"
    prefix="logic" %>
    &lt;logic:redirect <strong>action="/Welcome"</strong>/></code>
</pre>
<hr/>

<p>
    At the top of the page, we import the "struts-logic" JSP tag library.
    (For more about the Struts JSP tags, see the <a
        href="http://struts.apache.org/struts-taglib/">Struts Taglib
    website</a>.)
    The page itself consists of a single tag that redirects to the "Welcome"
    action.
    The tag inserts the actual web address for the redirect when the page is
    rendered.
    But, where does the tag find the actual address to insert?
</p>

<h4><a name="welcome.do" id="welcome.do">Welcome.do</a></h4>

<p>
    The list of actions, along with other components,
    are registered through one or more Struts Action configuration files.
    The configuration files are written as XML documents and processed when
    the application starts.
    If we just wanted to forward to the welcome page, we could use a simple
    configuration element.
</p>
<hr/>
<h5>A simple "forward thru" action element</h5>
<pre><code>        &lt;!-- Display welcome page -->
    &lt;action
    path="/Welcome"
    <strong>forward="/Welcome.jsp" /></strong></code></pre>
<hr/>

<p>
    If someone asked for the Welcome action ("/Welcome.do"), the welcome.jsp
    page would be displayed in return.
</p>

<p>
    But if we peek at the configuration file for the MailReader,
    we find a slightly more complicated XML element for the Welcome action.
</p>
<hr/>
<h5>The Welcome action element</h5>
<pre><code>        &lt;!-- Display welcome page -->
    &lt;action
    path="/Welcome"
    <strong>
        type="org.apache.struts.apps.mailreader.actions.WelcomeAction"</strong>
    >
    &lt;forward
    name="Success"
    path="/Welcome.jsp" />
    &lt;/action></code></pre>
<hr/>

<p>
    Here, the <strong>WelcomeAction</strong> Java class executes whenever
    someone asks for the Welcome action.
    As it completes, the Action class can select which "result" is displayed.
    One available result is "Success".
    Another available result, defined at a global scope, is "Failure".
    But the Action class doesn't need to know the path to the result, or even
    if they are server pages.
    The Action class can select the appropriate result just by using names
    like "Success" or "Failure".
</p>

<h4><a name="welcomeaction" id="welcomeaction">WelcomeAction</a></h4>

<p>
    OK ... but why would a WelcomeAction want to choose between Success and
    Failure?
</p>

<p>
    The MailReader application retains a list of users along with their email
    accounts.
    The application stores this information in a database.
    If the application can't connect to the database, the application can't do
    its job.
    So before displaying the welcome page, the class checks to see if the
    database is available.
    The MailReader is also an internationalized application.
    So, the WelcomeAction checks to see if the message resources are available
    too.
    If both resources are available, the class forwards to the "Success" path.
    Otherwise, it forwards to the "Failure" path so that the appropriate error
    messages can be displayed.
</p>

<h4><a name="global-forwards" id="global-forwards">global-forwards</a></h4>

<hr/>
<h5>MailReader's global-forward element</h5>
<pre><code>    &lt;!-- ==== Global Forward Definitions ==== -->
    <strong>&lt;global-forwards></strong>
    &lt;forward
    name="Logoff"
    path="/Logoff.do"/>
    &lt;forward
    name="Logon"
    path="/Logon.do"/>
    &lt;forward
    name="Failure"
    path="/Error.jsp" />
    &lt;/global-forwards></code></pre>
<hr/>

<p>
    As mentioned, "Failure" is defined in a global scope.
    Other actions may have trouble connecting to the database later, or other
    unexpected errors may occur.
    The MailReader defines the "Failure" result as a Global Forward, so that
    any action can use it.
</p>

<h4><a name="MemoryDatabasePlugIn.java" id="MemoryDatabasePlugIn.java">MemoryDatabasePlugIn.java</a>
</h4>

<p>
    The database is exposed as an object stored in application scope.
    The database object is based on an interface.
    Different implementations of the database could be loaded without changing
    the rest of the application.
    But how is the database object loaded in the first place?
</p>

<p>
    One section of the Struts configuration is devoted to "PlugIns".
    When a Struts application loads, it also loads whatever PlugIns are
    specified in its configuration.
    The PlugIn interface is quite simple.
</p>

<hr/>
<h5>org.apache.struts.action.PlugIn</h5>
<pre><code>public interface PlugIn {

    void <strong>destroy</strong>();

    void <strong>init</strong>(ActionServlet servlet, ModuleConfig config)
    throws ServletException;
    }</code></pre>
<hr/>

<p>
    You can use PlugIns to do anything that might need to be done when your
    application loads.
    The PlugIn is also notified when the application shuts down, so you can
    release any allocated resources.
</p>
<hr/>
<h5>The Database PlugIn element</h5>
<pre><code>    &lt;plug-in
    className="org.apache.struts.apps.mailreader.plugin.<strong>
    MemoryDatabasePlugIn</strong>">
    &lt;set-property
    property="pathname"
    value="/WEB-INF/database.xml"/>
    &lt;/plug-in>
</code></pre>
<hr/>

<p>
    By default, the MailReader application loads a "MemoryDatabase"
    implementation of the UserDatabase.
    MemoryDatabase stores the database content as a XML document,
    which is parsed and loaded as a set of nested hashtables.
    The outer table is the list of user objects, each of which has its own
    inner hashtable of subscriptions.
    When you register, a user object is stored in this hashtable ...
    and when you login, the user object is stored within the session context.
</p>

<p>
    The database comes seeded with a sample user.
    If you check the database.xml file under WEB-INF, you'll see the sample
    user described in XML.
</p>

<hr/>
<h5>The "seed" user element from the MailReader database.xml</h5>
<pre><code>  &lt;user username="user" fromAddress="John.User@somewhere.com"
    fullName="John Q. User" password="pass">
    &lt;subscription host="mail.hotmail.com" autoConnect="false"
    password="bar" type="pop3" username="user1234">
    &lt;/subscription>
    &lt;subscription host="mail.yahoo.com" autoConnect="false" password="foo"
    type="imap" username="jquser">
    &lt;/subscription>
    &lt;/user></code>
</pre>
<hr/>

<p>
    The "seed" user element creates a registration record for "John Q. User",
    with the detail for his hotmail account (or "subscription").
</p>

<h4><a name="MessageResources.properties" id="MessageResources.properties">MessageResources.properties</a>
</h4>

<p>
    Another section of the Struts configuration loads the message resources
    for the application.
    If you change a message in the resource, and then reload the application,
    the change will appear throughout the application.
    If you provide message resources for additional locales, you can
    internationalize your application.
</p>

<hr/>
<h5>The MailReader message-resources element</h5>
<pre><code>    &lt;message-resources
    parameter="org.apache.struts.apps.mailreader.resources.ApplicationResources"/></code>
</pre>
<hr/>

<p>
    The "ApplicationResources" parameter refers to a standard properties text
    file.
    The resource might be embedded in a JAR or kept under the WEB-INF/classes
    folder.
    MailReader uses the classes folder, which means its working copy of the
    ApplicationResources can be found at
    <code>
        ./WEB-INF/classes/org/apache./struts/apps/mailreader/resources/ApplicationResources"</code>
</p>

<p>
    The first time a page needs one of the resources, Struts Action loads and
    caches the properties file,
    so that the framework does not need to read the text file a second time.
</p>
<hr/>
<h5>ApplicationResource entries used by the Welcome page</h5>
<pre><code><strong>index.heading=</strong>MailReader Demonstration Application
    Options
    <strong>index.logon=</strong>Log on to the MailReader Demonstration
    Application
    <strong>index.registration=</strong>Register with the MailReader
    Demonstration Application
    <strong>index.title=</strong>MailReader Demonstration Application
    <strong>index.tour=</strong>A Walking Tour of the MailReader Demonstration
    Application</code></pre>
<hr/>

<p>
    The MailReader application uses a second set of message resources for
    non-text elements.
</p>

<hr/>
<h5>The MailReader <em>alternate</em> message-resources element</h5>
<pre><code>    &lt;message-resources
    parameter="org.apache.struts.apps.mailreader.resources.AlternateApplicationResources"
    key="alternate"/></code></pre>
<hr/>

<p>
    The "key" element can be used to access this resource bundle rather than
    the default bundle.
</p>

<h3><a name="welcome.jsp" id="welcome.jsp">Welcome page</a></h3>

<p>
    After confirming that the necessary resources exist, the WelcomeAction
    forwards to the Welcome page.
</p>
<hr/>
<h5>Welcome.jsp</h5>
<pre><code>&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
    &lt;%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %&gt;
    &lt;%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %&gt;

    &lt;html&gt;
    &lt;head&gt;
    &lt;title&gt;&lt;<strong>bean:message</strong> key="index.title"/&gt;&lt;/title&gt;
    &lt;link rel="stylesheet" type="text/css" href="base.css" /&gt;
    &lt;/head&gt;

    &lt;h3&gt;&lt;bean:message key="index.heading"/&gt;&lt;/h3&gt;
    &lt;ul&gt;
    &lt;li&gt;&lt;<strong>html:link</strong> action="/EditRegistration"&gt;
    &lt;bean:message key="index.registration"/&gt;&lt;/html:link&gt;&lt;/li&gt;
    &lt;li&gt;&lt;html:link action="/Logon"&gt;&lt;bean:message
    key="index.logon"/&gt;&lt;/html:link&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;h3&gt;Change Language&lt;/h3&gt;
    &lt;ul&gt;
    &lt;li&gt;&lt;html:link action="/Locale?language=en"&gt;English&lt;/html:link&gt;&lt;/li&gt;
    &lt;li&gt;&lt;html:link action="/Locale?language=ja"
    useLocalEncoding="true"&gt;Japanese&lt;/html:link&gt;&lt;/li&gt;
    &lt;li&gt;&lt;html:link action="/Locale?language=ru"
    useLocalEncoding="true"&gt;Russian&lt;/html:link&gt;&lt;/li&gt;
    &lt;/ul&gt;

    &lt;hr /&gt;

    &lt;p&gt;&lt;<strong>html:img</strong> bundle="alternate"
    pageKey="struts.logo.path" altKey="struts.logo.alt"/&gt;&lt;/p&gt;

    &lt;p&gt;&lt;html:link action="/Tour"&gt;&lt;bean:message
    key="index.tour"/&gt;&lt;/html:link&gt;&lt;/p&gt;

    &lt;/body&gt;
    &lt;/html&gt;</code></pre>
<hr/>

<p>
    At the top of the Welcome page, there are several directives that load the
    Struts tag libraries.
    These are just the usual red tape that goes with any JSP file.
    The rest of the page utilizes three Struts JSP tags: "bean:message",
    "html:link", and "html:img".
</p>

<p>
    The <strong>bean:message</strong> tag inserts a message from the
    MessageResources we mentioned in the last section.
    The MailReader comes with support for three locales: English (the
    default), Russian, and Japanese.
    If the Struts Action locale setting is changed for a user,
    the bean:message tag will render messages from that locale's property
    bundle instead.
</p>

<p>
    The <strong>html:link</strong> tag does double duty.
    First, you can refer to an action or forward stored in the Struts
    configuration,
    and the tag will insert the corresponding path when the page is rendered.
    This makes it easy to "rewire" an application without touching all the
    pages.
    Second, the link tag will "URL encode" the hyperlink to maintain the
    client session.
    Your application can maintain client state without requiring cookies.
</p>

<hr/>
<h5>Tip:</h5>
<blockquote>
    <p><font class="hint">
        <strong>Cookies</strong> -
        If you turn cookies off in your browser, and then reload your browser
        and this page,
        you will see the links with the Java session id information attached.
        (If you are using Internet Explorer and try this,
        be sure you reset cookies for the appropriate security zone,
        and that you disallow "per-session" cookies.)
    </font></p>
</blockquote>
<hr/>

<p>
    The <strong>html:img</strong> tag renders an img tag.
    When necessary, the src URI is encoded as it is with the link tag.
    In this case, the tag inserts the src path from the "alternate"
    MessageResource bundle,
    along with the text for the alt element.
</p>

<p>
    In the span of a single request for the Welcome page, Struts has done
    quite a bit already:
</p>

<ul>
    <li>
        Confirmed that required resources were loaded during initialization.
    </li>

    <li>
        Written all the page headings and labels from internationalized
        message resources.
    </li>

    <li>
        Automatically URL-encoded paths as needed.
    </li>
</ul>

<p>
    When rendered, the Welcome page lists two menu options:
    one to register with the application and one to login in (if you have
    already registered).
    Let's follow the Login link first.
</p>

<h3><a name="Logon.jsp" id="Logon.jsp">Logon Page</a></h3>

<p>
    If you choose the Logon link, and all goes well, the Logon action forwards
    control to the Logon.jsp page.
    The Logon page displays a form that accepts a username and password.
    You can use the default username and password to logon (user and pass) if
    you like.
</p>

<p>
    Note that both the username and password are case sensitive.
    Better yet, try omitting or misspelling the username and password in
    various combinations to
    see how the application reacts.
</p>

<hr/>
<h5>Login.jsp</h5>
<pre><code>&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
    &lt;%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %&gt;
    &lt;%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %&gt;

    &lt;html:xhtml/&gt;
    &lt;html&gt;
    &lt;head&gt;
    &lt;title&gt;&lt;bean:message key="logon.title"/&gt;&lt;/title&gt;
    &lt;/head&gt;

    &lt;<strong>html:errors</strong>/&gt;

    &lt;<strong>html:form</strong> action="/SubmitLogon" focus="username"
    onsubmit="return validateLogonForm(this);"&gt;
    &lt;table border="0" width="100%"&gt;

    &lt;tr&gt;
    &lt;th align="right"&gt;
    &lt;bean:message key="prompt.username"/&gt;:
    &lt;/th&gt;
    &lt;td align="left"&gt;
    &lt;<strong>html:text</strong> property="username" size="16"
    maxlength="18"/&gt;
    &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
    &lt;th align="right"&gt;
    &lt;bean:message key="prompt.password" bundle="alternate"/&gt;:
    &lt;/th&gt;
    &lt;td align="left"&gt;
    &lt;<strong>html:password</strong> property="password" size="16"
    maxlength="18"
    redisplay="false"/&gt;
    &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
    &lt;td align="right"&gt;
    &lt;<strong>html:submit</strong> property="Submit" value="Submit"/&gt;
    &lt;/td&gt;
    &lt;td align="left"&gt;
    &lt;<strong>html:reset</strong>/&gt;
    &lt;/td&gt;
    &lt;/tr&gt;

    &lt;/table&gt;

    &lt;/html:form&gt;

    &lt;<strong>html:javascript</strong> formName="LogonForm"
    dynamicJavascript="true"
    staticJavascript="false"/&gt;
    &lt;script language="Javascript1.1" src="StaticJavascript.jsp"&gt;&lt;/script&gt;

    &lt;jsp:include page="Footer.jsp" /&gt;
    &lt;/body&gt;
    &lt;/html&gt;</code>
</pre>
<hr/>

<p>
    We saw some of these tags on the Welcome page. Let's focus on the new
    tags.
</p>

<p>
    The first new tag on the logon page is <strong>html:errors</strong>.
    The credentials you entered are validated and processed by a "LogonAction"
    class.
    If the credentials are incorrect,
    the LogonAction posts an appropriate error message and forwards back to
    the input page.
    If the html:errors tag sees that one or more messages were posted, the tag
    ouputs the messages to the page.
    The text of the messages can be specified in the MessageResource bundle,
    making them easy to localize.
</p>

<p>
    The second new tag is <strong>html:form</strong>.
    This tag renders a html form tag.
    The "action" attribute tells the tag to use "SubmitLogon.do" for the
    form's action.
    The "focus" attribute tells the tag to generate a little Javascript into
    the form that
    sets its focus to the "username" field.
    The "onsubmit" attribute tells the form to run a Javascript when the form
    is submitted.
    (Just like the corresponding attribute on the standard form tag.)
</p>

<p>
    Within the html:form tag,
    we see five more new tags: "html:text", "html:password", "html:submit",
    "html:reset", and "html:javascript".
</p>

<p>
    The <strong>html:text</strong> tag renders a "input type=text" tag.
    The "property" attribute becomes the input tag's "name" attribute.
</p>

<p>
    The <strong>html:password</strong> tag renders a "input type=password"
    tag.
    The "redisplay" attribute tell the tag not to render the password back
    into the file, if the submit fails.
    The <strong>html:submit</strong> and <strong>html:reset</strong> tags
    render buttons of the corresponding types.
</p>

<p>
    Following the form is a <strong>html:javascript</strong> tag.
    This tag works with the Struts Validator component to generate a
    JavaScript that can validate input
    before it is submitted to the LogonAction.
</p>

<hr/>
<h5>Tip:</h5>
<blockquote>
    <p><font class="hint">
        Most of these tags have many more options than the ones we use in this
        application.
        For the complete documentation for each tag,
        see the Tag Developer Guides in the Struts Taglib documentation
        bundle.
    </font></p>
</blockquote>
<hr/>

<p>
    But, how do these tags know so much?
    How does the Javascript tag know what scripts to write?
    How do the text and password tags know what values to redisplay?
</p>

<p>
    For the answers, we need to turn back to the Struts Action Framework
    configuration files,
    "struts-config.xml" and "validation.xml".
</p>

<h4><a name="struts-config.xml" id="struts-config.xml">struts-config.xml</a>
</h4>

<p>
    The Struts configuration file is parsed by the ActionServlet when the
    application first load.
</p>

<h5>web.xml -- Action Servlet Configuration</h5>
<pre><code>
    &lt;servlet>
    &lt;servlet-name>action&lt;/servlet-name>
    &lt;servlet-class>org.apache.struts.action.ActionServlet&lt;/servlet-class>
    &lt;init-param>
    &lt;param-name>config&lt;/param-name>
    &lt;param-value><strong>/WEB-INF/struts-config.xml</strong>&lt;/param-value>
    &lt;/init-param>
    &lt;load-on-startup>1&lt;/load-on-startup>
    &lt;/servlet>
</code></pre>

<hr/>
<h5>The SubmitLogon action element</h5>
<pre><code>        &lt;!-- Process a user logon -->
    &lt;action
    <strong>path="/SubmitLogon"</strong>
    type="org.apache.struts.apps.mailreader.actions.LogonAction"
    <strong>name</strong>="LogonForm"
    <strong>scope</strong>="request"
    <strong>validate</strong>="request"
    <strong>input</strong>="Logon">
    &lt;<strong>exception</strong>
    key="expired.password"
    type="org.apache.struts.apps.mailreader.dao.ExpiredPasswordException"
    path="/ChangePassword.jsp"/>
    &lt;forward
    name="Success"
    path="/MainMenu.do"/>
    &lt;/action></code></pre>
<hr/>

<p>
    We saw the path and type attributes in the Welcome action.
    Let's look at the new attributes: "name", "scope", "input", and
    "exception".
</p>

<h4>The "name" attribute</h4>

<p>
    The <strong>name</strong> attribute specifies something Struts Action
    calls an "ActionForm".
    The ActionForm buffers input from a form and delivers it to an Action
    class as an object.
    The ActionForm can also be used to validate input.
    If validation fails, the tags can rewrite the input values from the
    ActionForm.
</p>

<p>
    The ActionForms are defined in the "form-beans" section of struts-config.
</p>

<p>
    ActionForms can be "conventional" or "dynamic".
    MailReader uses dynamic ActionForms.
    Rather than cobble up an actual JavaBean class,
    we specify the properties the ActionForm can accept in the configuration
    file.
</p>

<hr/>
<h5>The form-bean element for LogonForm</h5>
<pre><code>        &lt;!-- LogonAction form bean -->
    &lt;form-bean
    name="LogonForm"
    <strong>extends="BaseForm"/></strong></code></pre>
<hr/>

<p>
    Hmmmm. That doesn't seem to tell us much.
    The LogonForm "extends" the BaseForm, but doesn't add any attributes.
    What about the BaseForm element that LogonForm extends?
</p>

<hr/>
<h5>BaseForm - An "abstract" form-bean</h5>
<pre><code>        &lt;!-- BaseAction form bean (abstract) -->
    &lt;form-bean
    name="BaseForm"
    type="org.apache.struts.validator.DynaValidatorForm">
    <strong>&lt;form-property</strong>
    name="username"
    type="java.lang.String"/>
    &lt;form-property
    name="password"
    type="java.lang.String"/>
    &lt;form-property
    name="task"
    type="java.lang.String"
    initial="Create"/>
    &lt;/form-bean></code></pre>
<hr/>

<h5>Note:</h5>
<blockquote>
    <p><font class="hint">
        <strong>Extends</strong> - In the Struts configuration file,
        we can use the "extends" attribute to adopt default settings from
        another element.
        Extends makes using XML elements more like object-orientated
        programming.
        You can setup a base element, and then only specify the behavior that
        changes.
    </font></p>
</blockquote>
<hr/>

<p>
    Struts creates the ActionForms automatically, regardless of whether the
    form-bean is conventional or dynamic.
    The ActionForm lets us specify which properties we want to extract from
    the incoming request.
    If a property is not specified by the ActionForm,
    the value is not automatically transferred from the request, validated,
    or passed to the Action class.
</p>

<h4>The "scope" attribute</h4>

<p>
    The <strong>scope</strong> attribute in the "SubmitLogon" action element
    tells the controller whether to store the ActionForm in the request,
    rather than in the user's session.
</p>

<hr/>
<h5>Best Practice:</h5>
<blockquote>
    <p><font class="hint">
        Use request scope for single-page forms that contain all the
        properties needed by the Action.
        There is usually no need to maintain form input across requests.
    </font></p>
</blockquote>
<hr/>

<h4>The "validate" attribute</h4>

<p>
    The <strong>validate</strong> attribute controls whether the framework
    will automatically validate
    the ActionForm.
    Conventional ActionForms have a stub "validate" method that you can
    implement.
    MailReader uses the Validator framework instead,
    so the validations are specified in another configuration file.
</p>

<h4>The "input" attribute</h4>

<p>
    If validation fails, Struts looks for the forward specified by the
    <strong>input</strong> attribute.
    In this case, invoking the global "Logon" forward sends control back to
    the Logon page.
</p>

<h4>The "exception" element</h4>

<p>
    Within the SubmitLogon action element is another new element, <strong>
    exception</strong>.
    When a user logons on, it's possible that an "ExpiredPasswordException"
    will be thrown.
    Should this happen, Struts will catch the exception and send control to
    the "ChangePassword" action.
</p>

<hr/>
<h5>Change Password screen</h5>
<blockquote>
    <p>
        Your password has expired. Please ask the system administrator to
        change it. <u>Try Again</u>
    </p>
</blockquote>
<hr/>

<p>
    OK, it's not the greatest "Change Password" screen -- but, remember, this
    is still the first iteration!
</p>

<h4><a name="validations.xml" id="validations.xml">validations.xml</a></h4>

<p>
    In the Logon page, we mentioned that the html:javascript tag confers with
    the Struts Validator components.
    The Validator is configured through another XML document, the <strong>
    validation.xml</strong>.
</p>

<hr/>
<h5>Validator element for LogonForm</h5>
<pre><code>        &lt;form
    name="LogonForm">

    &lt;field
    property="<strong>username</strong>"
    depends="required">
    &lt;arg
    key="prompt.username"/>
    &lt;/field>

    &lt;field
    property="<strong>password</strong>"
    depends="required, minlength,maxlength">
    &lt;arg
    key="prompt.password"/>
    &lt;arg
    key="${var:minlength}"
    name="minlength"
    resource="false"/>
    &lt;arg
    key="${var:maxlength}"
    name="maxlength"
    resource="false"/>

    &lt;var>
    &lt;var-name>
    maxlength
    &lt;/var-name>
    &lt;var-value>
    16
    &lt;/var-value>
    &lt;/var>
    &lt;var>
    &lt;var-name>
    minlength
    &lt;/var-name>
    &lt;var-value>
    3
    &lt;/var-value>
    &lt;/var>
    &lt;/field>

    &lt;/form></code></pre>
<hr/>

<p>
    The field elements correspond to the ActionForm properties.
    The <strong>username</strong> field element says it depends on the
    "required" validator.
    If the username is blank or absent, validation will fail and an error
    message is automatically generated.
</p>

<p>
    The <strong>password</strong> field (or property) is also required.
    In addition, it must also pass the "maxlength" and "minlength"
    validations.
    Here, the minimum length is three characters and the maximum length is
    sixteen.
    If the length of the password doesn't meet these criteria, a corresponding
    error message is generated.
    Of course, the messages are generated from the MessageResource bundles and
    are easy to localize.
</p>

<h4><a name="LogonAction.java" id="LogonAction.java">LogonAction.java</a></h4>

<p>
    If validation passes, the LogonForm object is passed to the LogonAction as
    a parameter.
    The LogonAction interacts with the database to see if the credentials are
    valid.
    If so, the user is logged on, and control passes to the "success" forward.
    Otherwise, control is forwarded to the input page and the list of error
    messages displayed.
</p>

<hr/>
<h5>LogonAction.java</h5>
<pre><code> public final class <strong>LogonAction</strong> extends BaseAction
    {
    public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws Exception {

    // Retrieve user
    String username = <strong>doGet</strong>(form, USERNAME);
    String password = doGet(form, PASSWORD);
    ActionMessages errors = new ActionMessages();
    User user = <strong>doGetUser</strong>(username,password,errors);

    // Report back any errors, and exit if any
    if (!errors.isEmpty()) {
    this.saveErrors(request, errors);
    return (mapping.getInputForward());
    }

    // Cache user object in session to signify logon
    <strong>doCacheUser</strong>(request,user);

    // Done
    return <strong>doFindSuccess</strong>(mapping);
    }
    }</code></pre>
<hr/>

<p>
    LogonAction extends another Action class, BaseAction.
    The BaseAction class provides a number of helper methods, all of which are
    prefixed with "do".
    The <strong>doCacheUser</strong> method, for example, stores the user
    object in the session,
    and logs the event, if the logging level is set to debug.
</p>

<hr/>
<h5>BaseAction.doCacheUser</h5>
<pre><code> void <strong>doCacheUser</strong>(HttpServletRequest request, User
    user) {

    HttpSession session = request.getSession();
    session.setAttribute(Constants.USER_KEY, user);
    if (log.isDebugEnabled()) {
    log.debug(
    "LogonAction: User '"
    + user.getUsername()
    + "' logged on in session "
    + session.getId());
    }
    }
</code></pre>
<hr/>

<p>
    Because our ActionForm is a DynaActionForm,
    we can't access or change the properties directly using methods like
    "getUsername".
    To make working with DynaActionForm properties easier,
    BaseAction provides two simple helper methods, <strong>doGet</strong> and
    <strong>doSet</strong>.
    These are utility methods that you caould use in any Struts application.
</p>

<hr/>
<h5>BaseAction.doGet and doSet</h5>
<pre><code> protected String <strong>doGet</strong>(ActionForm form, String
    property) {
    String initial;
    try {
    initial = (String) PropertyUtils.getSimpleProperty(form, property);
    } catch (Throwable t) {
    initial = null;
    }
    String value = null;
    if ((initial !=null) && (initial.length()>0)) {
    value = initial.trim();
    if (value.length()==0) value = null;
    }
    return value;
    }

    protected boolean <strong>doSet</strong>(ActionForm form, String property,
    String value) {
    try {
    DynaActionForm dyna = (DynaActionForm) form;
    dyna.set(property,value);
    } catch (Throwable t) {
    return false;
    }
    return true;
    }</code></pre>
<hr/>

<p>
    LogonAction uses two other BaseAction helpers: "doGetUser" and
    "doFindSuccess".
</p>

<hr/>
<h5>BaseAction.doGetUser</h5>
<pre><code> User <strong>doGetUser</strong>(UserDatabase database, String
    username,
    String password, ActionMessages errors)
    throws ExpiredPasswordException {

    User user = null;
    if (database == null){
    errors.add(
    ActionMessages.GLOBAL_MESSAGE,
    new ActionMessage("error.database.missing"));
    }
    else {
    user = <strong>database.</strong>findUser(username);
    if ((user != null) && !user.getPassword().equals(password)) {
    user = null;
    }
    if (user == null) {
    errors.add(
    ActionMessages.GLOBAL_MESSAGE,
    new ActionMessage("error.password.mismatch"));
    }
    }

    return user;
    }
</code></pre>
<hr/>

<p>
    The <strong>doGetUser</strong> helper does the real work of the
    LogonAction.
    The "doGetUser" method checks the tendered credentials against the
    database,
    If there are any issues, like there is not a user by that name, or the
    password doesn't match, doGetUser passes back the appropriate messages.
</p>

<p>
    The doGet user is another "facade" method.
    A facade simplifies a complicated call to a business method.
    Here, doGetUser wrapes the business method with the Error Handling needed
    by the Mail Reader application.
</p>

<hr/>
<h5>BaseAction.doFindSuccess</h5>
<pre><code> protected ActionForward <strong>doFindSuccess</strong>
    (ActionMapping mapping) {
    if (log.isTraceEnabled()) {
    log.trace(Constants.LOG_SUCCESS);
    }
    return mapping.findForward(Constants.SUCCESS);
</code></pre>
<hr/>

<p>
    The <strong>doFindSuccess</strong> method is a simple utility but often
    used.
    It just checks the mapping for a result named "Success".
    By using a utility,
    we can include a logging statement when trace is enabled,
    and be very sure that everyone knows how to spell "Success". :)
</p>

<h4><a name="MainMenu.do" id="MainMenu.do">MainMenu.do and MainMenu.jsp</a>
</h4>

<p>
    On a successful logon, the Main Menu page displays.
    If you logged in using the demo account, the page title should be "Main
    Menu Options for John Q. User".
    Below this legend should be two links:
</p>

<ul>
    <li>
        Edit your user registration profile
    </li>
    <li>
        Log off MailReader Demonstration Application
    </li>
</ul>

<p>
    If you check the address shown by your browser,
    you will see that it shows "/SubmitLogon.do" not "/MainMenu.do".
    The Java servlet platform supports the idea of server-side forwards.
    When control passed from the SubmitLogon action to the MainMenu action,
    everything occured server-side.
    All the browser knows is that we are looking at the result of submitting a
    form to "/SubmitLogon.do",
    so that's the address that shows.
    It doesn't know control passed from one action to another.
    The difference between server-side forwards and client-side redirects is
    subtle
    and often confuses new developers.
</p>

<p>
    If you change the address to "/MainMenu.do" and press enter, the same page
    will display again,
    but only because you are logged on.
    If you bookmark MainMenu.do, log off, and try to return later, the system
    will force you to logon first.
</p>

<p>
    Let's review the source for the "MainMenu" action mapping,
    "MainMenuAction.java" class, and the "MainMenu.jsp".
</p>

<hr/>
<h5>Action mapping element for MainMenu</h5>
<pre><code>        &lt;!-- Display MainMenu -->
    &lt;action
    <strong>path="/MainMenu"</strong>
    type="org.apache.struts.apps.mailreader.actions.MainMenuAction">
    &lt;forward
    name="Success"
    path="/MainMenu.jsp"/>
    &lt;/action></code></pre>

<h5>MainMenuAction.java</h5>
<pre><code>public final class MainMenuAction extends BaseAction {

    public ActionForward <strong>execute</strong> (
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws Exception {

    User user = doGetUser(request);
    if (user==null) return <strong>doFindLogon</strong>(mapping);
    return <strong>doFindSuccess</strong>(mapping);
    }

    }</code></pre>

<h5>MainMenu.jsp</h5>
<pre><code>&lt;%@ page contentType="text/html;charset=UTF-8" language="java"
    %>
    &lt;%@ taglib uri="/tags/app" prefix="app" %>
    &lt;%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %>
    &lt;%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>
    &lt;html>
    &lt;head>
    &lt;title>&lt;bean:message key="mainMenu.title"/>&lt;/title>
    &lt;link rel="stylesheet" type="text/css" href="base.css" />
    &lt;/head>
    &lt;h3>&lt;bean:message key="mainMenu.heading"/> &lt;<strong>
    bean:write</strong> name="user" property="fullName" />&lt;/h3>
    &lt;ul>
    &lt;li>&lt;html:link action="/EditRegistration">&lt;bean:message
    key="mainMenu.registration"/>&lt;/html:link>&lt;/li>
    &lt;li>&lt;html:link action="/Logoff">&lt;bean:message
    key="mainMenu.logoff"/>&lt;/html:link>&lt;/li>
    &lt;/ul>
    &lt;/body>
    &lt;/html></code></pre>
<hr/>

<p>
    In the MainMenuAction, we find two new helper methods: "doFindLogon" and
    "doFindSuccess".
</p>

<p>
    The <strong>doFindLogon</strong> helper locates the "logon" result,
    and logs the event if trace logging is enabled.
    If someone has bookmarked "MainMenu.do" and tries to return without
    logging in,
    the MainMenuAction sends the request to Logon.do instead.
</p>

<hr/>
<h5>BaseAction.doFindLogon</h5>
<pre><code> protected ActionForward <strong>doFindLogon</strong>(ActionMapping
    mapping) {
    if (log.isTraceEnabled()) {
    log.trace(Constants.LOG_LOGON);
    }
    <strong>return mapping.findForward(Constants.LOGON);</strong>
    }
</code></pre>

<p>
    Likewise, <strong>doFindSuccess</strong> locates the "success" result,
    and logs the event if trace logging is enabled.
</p>

<hr/>
<h5>BaseAction.doFindSuccess</h5>
<pre><code> protected ActionForward <strong>doFindSuccess</strong>
    (ActionMapping mapping) {
    if (log.isTraceEnabled()) {
    log.trace(Constants.LOG_SUCCESS);
    }
    <strong>return mapping.findForward(Constants.SUCCESS);</strong>
    }</code></pre>
<hr/>

<p>
    The source for MainMenu.jsp also contains a new tag, <strong>
    bean:write</strong>.
    When control passed through the LogonAction,
    it retrieved a "user" object from the database and stored a reference in
    "session" scope.
    This object is a JavaBean with several properties.
    One property is "fullName".
    The bean:write tag can find the User bean and print the fullName property
    for us.
</p>

<p>
    Since the MainMenuAction verifies that the User object exists,
    the MainMenu page can refer to the object without ado.
    The application does not reveal the location of any server page on the
    browser address bar,
    but if you did happen to know the address for the server page, and you did
    enter it directly,
    the tag would throw an exception, and the framework would transfer to the
    standard error page.
</p>

<hr/>
<h5>Error.jsp</h5>
<pre><code> An unexpected error has occured

    Cannot find bean: "user" in any scope

    <u>MailReader Demonstration Application</u></code></pre>
<hr/>

<p>
    The MainMenu action doesn't have an exception handler of its own,
    so it falls back to the standard handler in the MailReader web.xml.
</p>

<hr/>
<h5>error-page element in web.xml</h5>
<pre><code>        &lt;!-- The default error page -->
    &lt;error-page>
    &lt;exception-type>java.lang.Exception&lt;/exception-type>
    &lt;location>/Error.jsp&lt;/location>
    &lt;/error-page></code></pre>
<hr/>

<p>
    Meanwhile, The MainMenu page offers two links.
    One link is to the "Logoff" action.
    The other is to "EditRegistration".
    Hmmmm, back on the Welcome page, we also linked to the EditRegistration
    action to create an account.
    Which is it? Insert or Update?
</p>

<h4><a name="EditRegistration.do" id="MainMenu.do">EditRegistration.do</a>
</h4>

<p>
    If you scan the struts-config for an EditRegisration action, you won't
    find one.
    Instead, you will find a "/Edit*" action.
    The asterisk is a wildcard character that lets you apply a common action
    configuration
    to any request that beings with "Edit".
</p>

<hr/>
<h5>The Wilcard Edit* action and the BaseAction element it extends</h5>
<pre><code>        &lt;action
    path="/Edit<strong>*</strong>"
    extends="//BaseAction"
    <strong>parameter</strong>="Edit"
    validate="false"/>

    &lt;!-- "Abstract" mapping to use as base -->
    &lt;action path="//BaseAction"
    input="Input"
    type="org.apache.struts.apps.mailreader.actions.<strong>{1}</strong>
    Action"
    name="<strong>{1}</strong>Form"
    scope="request">
    &lt;forward
    name="Success"
    path="/"<strong>{1}</strong>.jsp"/>
    &lt;forward
    name="Input"
    path="/"<strong>{1}</strong>.jsp"/>
    &lt;/action></code></pre>
<hr/>

<p>
    The <strong>Edit*</strong> action extends the "BaseAction" element (as do
    other Wilcard actions),
    and provides two attibutes of its own: "validate" and "parameter".
    Validate we've seen before, but what about "parameter"?
</p>

<p>
    The Action class underlying the EditRegistration action extends a standard
    Struts class called
    "MappingDispatchAction".
    Usually, an Action has one entry point, the "execute" method.
    Dispatch Actions let you define multiple entry points to an Action.
    People find Dispatch Actions handy for related actions, like editing or
    saving the same entity.
    (In our case, a Registration.)
</p>

<p>
    A <strong>MappingDispatchAction</strong> uses the parameter attribute to
    determine
    which method to use as the entry point.
    Each dispatch entry point is a separate method, but each method must same
    signature as execute.
    In this case, we're telling the framework to call the "Edit" method when
    this action is invoked.
</p>

<p>
    OK, but how do we know which Action class to call? The "Edit*" action
    mapping doesn't specify a type attribute.
</p>

<p>
    If you look at the BaseAction mapping,
    you'll see that it does specify a type attribute, but the class name isn't
    valid.
    It contains a "{1}" token instead of the fully qualified class name.
</p>

<p>
    Since the type attribute will be used with a Wildcard action ("/Edit*"),
    we can use the {1} to represent the first Wildcard replaced in the path.
    In the case of EditRegistration, the "wild" text would be "Registration",
    so that's what is plugged into the type statement.
    Then the EditRegistration action is called,
    the type becomes "org.apache.struts.apps.mailreader.actions.<strong>
    Registration</strong>Action".
</p>

<p>
    The same thing will happen for the other markers.
    The ActionForm name becomes "RegistrationForm".
    The name of the "Success" server page becomes "Registration.jsp".
</p>

<p>
    The <strong>RegistrationForm</strong> is a DynaActionForm, much like the
    LoginForm.
</p>

<hr/>
<h5>The RegistrationForm form-bean element</h5>
<pre><code>    &lt;!-- RegistrationAction form bean -->
    &lt;form-bean
    name="RegistrationForm"
    <strong>extends="BaseForm"</strong>>
    &lt;form-property
    name="fromAddress"
    type="java.lang.String"/>
    &lt;form-property
    name="fullName"
    type="java.lang.String"/>
    &lt;form-property
    name="password2"
    type="java.lang.String"/>
    &lt;form-property
    name="replyToAddress"
    type="java.lang.String"/>
    &lt;/form-bean></code></pre>
<hr/>

<p>
    The <strong>RegistrationForm</strong> extends the BaseForm and adds
    properties peculiar to the Registration
    action.
    When either the Welcome page or MainMenu page link to "<strong>
    Edit</strong>Registration",
    the framework creates the RegistrationForm, autopopulates the form-bean
    properties from any matching attributes
    in the request, and invokes the <strong>Edit</strong> method of the
    RegistrationAction class.
</p>

<hr/>
<h5>RegistrationAction.Edit</h5>
<pre><code> public ActionForward <strong>Edit</strong>(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws Exception {

    final String method = Constants.EDIT;
    <strong>doLogProcess</strong>(mapping,method);

    HttpSession session = request.getSession();
    User user = <strong>doGetUser</strong>(session);
    boolean updating = (user!=null);
    if (updating) {
    <strong>doPopulate</strong>(form,user);
    }

    <strong>doSaveToken</strong>(request);
    return doFindSuccess(mapping);
    }
</code></pre>
<hr/>

<p>
    The <strong>RegistrationAction.Edit</strong> method does most of its work
    by calling various helper methods,
    including "doLogProcess", "doGetUser", "doPopulate", and "doSaveToken".
</p>

<hr/>
<h5>BaseAction.doLogProcess</h5>
<pre><code> protected void <strong>doLogProcess</strong>(ActionMapping
    mapping, String method) {
    if (log.isDebugEnabled()) {
    StringBuffer sb = new StringBuffer(128);
    sb.append(" ");
    sb.append(mapping.getPath());
    sb.append(":");
    sb.append(Constants.LOG_PROCESSING);
    sb.append(method);
    log.debug(sb.toString());
    }
    }</code></pre>
<hr/>

<p>
    MailReader uses <a href="http://jakarta.apache.org/commons/logging/">Commons
    Logging</a> from Apache Jakarta.
    Commons Logging is an API utility that can be used with several different
    logging systems.
    The <strong>doLogProcess</strong> helper is just a wrapper around a
    logging statement
    that MailReader uses in several places.
    All of the MailReader's Dispatch methods call this helper to log when
    control reaches the method.
</p>

<hr/>
<h5>BaseAction.doGetUser</h5>
<pre><code> protected User <strong>doGetUser</strong>(HttpSession session) {
    return (User) session.getAttribute(Constants.USER_KEY);
    }
</code></pre>
<hr/>

<p>
    Most of the MailReader actions utilize the User object,
    and so BaseAction encapsulates obtaining the User into the very simple
    <strong>doGetUser</strong> helper.
</p>

<hr/>
<h5>RegistrationAction.doPopulate</h5>
<pre><code> private void <strong>doPopulate</strong>(ActionForm form, User
    user) throws ServletException {

    final String title = Constants.EDIT;

    if (log.isTraceEnabled()) {
    log.trace(Constants.LOG_POPULATE_FORM + user);
    }

    try {
    PropertyUtils.copyProperties(form, user);
    DynaActionForm dyna = (DynaActionForm) form;
    <strong>dyna.set(TASK,title);</strong>
    dyna.set(PASSWORD,null);
    dyna.set(PASSWORD2,null);
    } catch (InvocationTargetException e) {
    Throwable t = e.getTargetException();
    if (t == null)
    t = e;
    log.error(LOG_REGISTRATION_POPULATE, t);
    throw new ServletException(LOG_REGISTRATION_POPULATE, t);
    } catch (Throwable t) {
    log.error(LOG_REGISTRATION_POPULATE, t);
    throw new ServletException(LOG_REGISTRATION_POPULATE, t);
    }
    }</code></pre>
<hr/>

<p>
    The <strong>doPopulate</strong> helper lives in RegistrationAction rather
    than BaseAction,
    since it involves the RegistrationForm, which only the RegistrationAction
    uses.
    The main job of doPopulate is to transfer the input values from the
    ActionForm to the User object.
    The constants, like "PASSWORD", are defined on RegisrationAction as public
    constants.
    These constants document the property names specified in the Struts
    configuration for the dynamic
    RegistrationForm.
</p>

<p>
    An interesting point is the line that sets the "TASK" to "Edit".
    This value is used by the server page to adjust the page title and form
    layout.
    When we defined the RegistrationForm, we set the default value for TASK to
    be "Create".
    When EditRegistration is called from the Welcome page, we don't have a
    User object yet,
    and so the TASK remains at "Create".
    When EditRegistration is called from the MainMenu page, we do have a User
    object,
    and so the TASK is set to "Edit".
</p>

<hr/>
<h5>BaseAction.doSaveToken</h5>
<pre><code> protected void doSaveToken(HttpServletRequest request) {
    if (log.isTraceEnabled()) {
    log.trace(Constants.LOG_TOKEN);
    }
    saveToken(request);
    }</code></pre>
<hr/>

<p>
    A common problem with designing web applications is that response times
    can vary and users are impatient.
    Sometimes, people will press a submit button a second time.
    When this happens, the browser submits the request again,
    so that we now have two requests for the same thing.
    In the case of registering a user, if someone does press the submit button
    again, and their timing is bad,
    it could result in the system reporting that the username has already been
    used.
    (The first time the button was pressed.)
    In practice, this would probably never happen, but for a longer running
    process, like verifying a
    credit card transaction, it's easier for a double submit to occur.
</p>

<p>
    To forestall double submits, the framework can generate a token that is
    embedded in the form
    and also kept in the session.
    If the value of the tokens do not compare, then we know that there has
    been a problem,
    and a form has been submitted twice or out of sequence.
</p>

<p>
    The <strong>doSaveToken</strong> helper, logs the event for tracking,
    and then calls the framework method.
    Later, when we Save the registration, we will check to see if the token is
    valid.
</p>

<p>
    After the token has been saved,
    Edit calls "doFindSuccess and" control flows to the Registration page.
</p>

<h3><a name="Registration.jsp" id="Registration.jsp">Registration page</a>
</h3>

<p>
    If you follow the "Edit your user registration profile" link from the Main
    Menu page,
    we will finally reach the heart of the MailReader application: the
    Registration, or "Profile", page.
    This page displays everything MailReader knows about you (or at least your
    login),
    while utilizing several interesting techniques.
</p>

<p>
    To do double duty as the "Create" Registration page and the "Edit"
    Registration page,
    the Registation.jsp makes good use of logic tags,
    to make it appears as though there are two distinct pages.
    For example, if you are editing the form (task == "Edit"),
    the page inserts your username from the RegistrationForm bean.
    If you are new user (task == "Create"), the page creates an empty field,
    so you can pick your username.
</p>

<hr/>
<h5>Note:</h5>
<blockquote>
    <p><font class="hint">
        <strong>Presention Logic</strong> -
        The Struts logic tags are a convenient way to express presentation
        logic within your pages.
        Customized pages help to prevent user error,
        and dynamic customization reduces the number of JSPs your application
        needs to maintain,
        among other benefits.
    </font></p>
</blockquote>
<hr/>

<p>
    The page also uses logic tags to display a list of subscriptions for the
    given user.
    If the RegistrationForm has task set to "Edit",
    the lower part of the page that lists the subscriptions is exposed.
</p>

<hr/>
<h5></h5>
<pre><code>&lt;logic:equal name="RegistrationForm" <strong>
    property="task"</strong>
    scope="request" <strong>value="Edit"</strong>>
    &lt;h3>&lt;bean:message key="heading.subscriptions"/>&lt;/h3>
    &lt;!-- ... -->
    &lt;html:link action="/EditSubscription">
    &lt;bean:message key="registration.addSubscription"/>
    &lt;/html:link>
    &lt;/logic:equal></code></pre>
<hr/>

<p>
    Otherwise, the page contains just the top portion --
    a blank data-entry form for creating the user's registration.
</p>

<h4><a name="logic:iterate" id="logic:iterate">logic:iterate</a></h4>

<p>
    Beside making the usual conditional tests,
    you can also use logic tags to forward control to other actions,
    to redirect control to another path, and to iterate over collections.
    The Registration page includes a good example of using the logic:iterate
    tag to display the user's subscriptions.
</p>

<p>
    The subscriptions are stored in a hashtable object, which is in turn
    stored in the user object.
    So to display each subscription, we have to reach into the user object,
    and loop through the members of the subscription collection.
    Using the iterate tag, you can code it the way it sounds.
</p>

<hr/>
<h5>Using logic:iterate to list the Subscriptions</h5>
<pre><code>    &lt;logic:iterate <strong>name</strong>="user" <strong>
    property</strong>="subscriptions" <strong>id</strong>="subscription">
    &lt;tr>
    &lt;td align="left">
    &lt;bean:write name="subscription" property="host"/>
    &lt;/td>
    &lt;td align="left">
    &lt;bean:write name="subscription" property="username"/>
    &lt;/td>
    &lt;td align="center">
    &lt;bean:write name="subscription" property="type"/>
    &lt;/td>
    &lt;td align="center">
    &lt;bean:write name="subscription" property="autoConnect"/>
    &lt;/td>
    &lt;td align="center">
    &lt;html:link action="/DeleteSubscription"
    <strong>paramName</strong>="subscription" <strong>paramProperty</strong>
    ="host" <strong>paramId</strong>="host">
    &lt;bean:message key="registration.deleteSubscription"/>
    &lt;/html:link>
    &nbsp;
    &lt;html:link action="/EditSubscription"
    paramName="subscription" paramProperty="host" paramId="host">
    &lt;bean:message key="registration.editSubscription"/>
    &lt;/html:link>
    &lt;/td>
    &lt;/tr>
    &lt;/logic:iterate></code></pre>
<hr/>

<p>
    The three parameters to the iterate tag (name, property, and id) tell it
    to
</p>

<ol>
    <li>
        <em>name</em> - Check this context for an attribute (e.g. object)
        named <strong>user</strong>,
    </li>

    <li>
        <em>property</em> - Snag the property of user named <strong>
        subscriptions</strong>,
    </li>

    <li>
        <em>id</em> - In the block to iterate,
        use <strong>subscription</strong> (singular) as the name for each
        member of the collection.
    </li>
</ol>

<p>
    Next to each entry in the subscription list are links to Delete and Edit
    commands.
    These links use the same name/property/id trinity as the interator,
    except that the attributes are used to create a hyperlink with a single
    parameter.
    (Multiple parameters are possible too, but if the code is well-factored,
    one should be sufficient.)
</p>

<p>
    Given a subscription to "mail.yahoo.com",
    the command links would translate to HTML links like these:
</p>

<hr/>
<h5>The Delete and Edit links for mail.yahoo.com</h5>
<pre><code>      &lt;a
    href="/struts-mailreader/DeleteSubscription.do?host=mail.yahoo.com">Delete&lt;/a>
    &nbsp;
    &lt;a
    href="/struts-mailreader/EditSubscription.do?host=mail.yahoo.com">Edit&lt;/a></code>
</pre>
<hr/>

<p>
    At the foot of the Register page is a link for adding a subscription.
    Let's wind up the tour by following the Add link and then logging off.
    Like the link for creating a Registration, Add points to an "Edit" action,
    namely "EditSubscription".
</p>

<h4>
    <a name="SubscriptionAction.java" id="SubscriptionAction.java">SubscriptionAction.java</a>
</h4>

<p>
    The EditSubscription link shares the Wildcard "/Edit*" mapping we saw with
    EditRegistration.
    As before, in the case of "Edit<em>Subscription</em>",
    the "{1}Form" attribute maps to <strong>SubscriptionForm</strong>.
</p>

<hr/>
<h5>The SubscriptionAction form-bean element</h5>
<pre><code>        &lt;form-bean
    name="SubscriptionForm"
    extends="BaseForm">
    &lt;form-property
    name="autoConnect"
    <strong>type="java.lang.Boolean"
        initial="FALSE"
        reset="true"</strong>/>
    &lt;form-property
    name="host"
    type="java.lang.String" />
    &lt;form-property
    name="type"
    type="java.lang.String" />
    &lt;/form-bean></code></pre>
<hr/>

<p>
    The other DynaActionForms we've seen used only String properties.
    SubscriptionForm is different in that it uses a Boolean type for the
    "autoConnect" property.
    On the HTML form, the autoConnect field is represented by a checkbox,
    and checkboxes need to be handled differently that other controls.
</p>

<hr/>
<h5>Tip:</h5>
<blockquote>
    <p class="hint">
        <strong>Checkboxes</strong> -
        The HTML checkbox is a tricky control.
        The problem is that, according to the W3C specification, a value is
        only guaranteed to be sent
        if the control is checked.
        If the control is not checked, then the control may be omitted from
        the request, as if it was on on the page.
        This can cause a problem with session-scope checkboxes.
        Once you set the checkbox to true, the control can't set it to false
        again,
        because if you uncheck the box, nothing is sent, and so the control
        stays checked.
    </p>

    <p class="hint">
        The simple solution is to set the initial value for a checkbox control
        to false before the form is populated.
        If the checkbox is checked, it will return a value, and the checkbox
        will represent true.
        If the checkbox is unchecked, it will not return a value, and the
        checkbox will remain unchecked ("false").
    </p>
</blockquote>
<hr/>

<p>
    To be sure the autoConnect checkbox is handled correctly,
    the SubscriptionForm initializes the property to FALSE,
    and enables "reset" so that before autopopulation the property is set back
    to FALSE.
</p>

<p>
    The SubscriptionAction Edit method should look familiar, but it also has a
    few twists of its own.
</p>

<hr/>
<h5>SubscriptionAction.Edit</h5>
<pre><code>public ActionForward Edit(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws Exception {

    final String method = Constants.EDIT;
    doLogProcess(mapping,method);

    HttpSession session = request.getSession();
    User user = doGetUser(session);
    <strong>if (user==null) return doFindLogon(mapping);</strong>

    // Retrieve the subscription, if there is one
    Subscription subscription;
    <strong>String host = doGet(form,HOST);
        boolean updating = (host!=null);</strong>
    if (updating) {
    subscription = <strong>doFindSubscription</strong>(user,host);
    if (subscription==null) return <strong>doFindFailure</strong>(mapping);
    session.setAttribute(Constants.SUBSCRIPTION_KEY, subscription);
    <strong>doPopulate</strong>(form,subscription);
    doSet(form,TASK,method);
    }

    return doFindSuccess(mapping);
    }</code></pre>
<hr/>

<p>
    In RegistrationAction.Edit, we looked for the user object to decide if we
    were updating or inserting.
    In SubscriptionAction.Edit, the user object is required (and we trot off
    to the Login page if it is missing).
    This could happen because a session expired, or because someone bookmarked
    a page.
</p>

<p>
    To decide if we are inserting or updating a subscription,
    we look to see if the <strong>host</strong> is set to the ActionForm.
    If it is an update, we fetch the Subscription from the database.
</p>

<hr/>
<h5>SubscriptionAction.doFindSubscription</h5>
<pre><code> private Subscription <strong>doFindSubscription</strong>(User
    user, String host) {

    Subscription subscription;

    try {
    subscription = user.findSubscription(host);
    }
    catch (NullPointerException e) {
    subscription = null;
    }

    if ((subscription == null) && (log.isTraceEnabled())) {
    log.trace(
    " No subscription for user "
    + user.getUsername()
    + " and host "
    + host);
    }

    return subscription;
    }</code></pre>
<hr/>

<p>
    If we can't find the subscription,
    we use <strong>doFindFailure</strong> to forward to the Failure result
    (Error.jsp).
</p>

<hr/>
<h5>BaseAction.doFindFailure</h5>
<pre><code> protected ActionForward <strong>doFindFailure</strong>
    (ActionMapping mapping) {
    if (log.isTraceEnabled()) {
    log.trace(Constants.LOG_FAILURE);
    }
    return (mapping.findForward(Constants.FAILURE));
    }
</code></pre>
<hr/>

<p>
    In the normal course, the subscription should always be found,
    since we selected the host from a system-generated list.
    If the subscription is not found,
    it would be because the database disappeared or the request is being
    spoofed.
</p>

<p>
    Like the RegisterAction, the <strong>doPopulate</strong> method transfers
    data from the form to the domain
    object. In this case, a Subscription object.
</p>

<hr/>
<h5>SubscriptionAction.doPopulate</h5>
<pre><code> private void <strong>doPopulate</strong>(ActionForm form,
    Subscription subscription) throws ServletException {

    final String title = Constants.EDIT;

    if (log.isTraceEnabled()) {
    log.trace(Constants.LOG_POPULATE_FORM + subscription.getHost());
    }

    try {
    <strong>PropertyUtils.copyProperties(form, subscription);</strong>
    doSet(form,TASK,title);
    } catch (InvocationTargetException e) {
    Throwable t = e.getTargetException();
    if (t == null) t = e;
    log.error(LOG_SUBSCRIPTION_POPULATE, t);
    throw new ServletException(LOG_SUBSCRIPTION_POPULATE, t);
    } catch (Throwable t) {
    log.error(LOG_SUBSCRIPTION_POPULATE, t);
    throw new ServletException(LOG_SUBSCRIPTION_POPULATE, t);
    }
    }</code></pre>
<hr/>

<p>
    Most of the code in "doPopulate" is window dressing for the call to
    <strong>PropertyUtils.copyProperties</strong>, which does the heavy
    lifting.
</p>

<p>
    But before turning to our final JSP, a word about our database model ...
</p>

<h4>
    <a name="User.java" id="User.java">User.java</a> and <a
        name="Subscription.java" id="Subscription.java">Subscription.java</a>
</h4>

<p>
    If you're used to working with relational databases,
    the links between the user and subscription objects may be confusing.
    A conventional relational database would create two distinct tables,
    one for the users and another for the subscriptions,
    and link them together with a user ID.
    The MailReader application implements a different model, a hierarchical
    database.
    Here a "table" of subscriptions is stored within each user object,
    something like the way a filing system stores documents within folders.
</p>

<p>
    Development teams often use frameworks like <a
        href="http://www.objectstyle.org/cayenne/">Cayenne</a>
    to map a relational database to a hierarchy of objects,
    like the one used by MailReader.
    For simplicity, the MailReader doesn't use a conventional database, but
    saves its data as an XML file.
    While the MailReader is running, the database is kept in main memory, and
    written to back to disk when changed.
</p>

<p>
    In addition to the usual getters and setters,
    the user object also has two methods for working with subscription
    objects.
    The <strong>findSubscription</strong> method takes a hostname and returns
    the subscription object for that host.
    The <strong>getSubscriptions</strong> method returns an array of all the
    subscriptions for the user
    (ready-made for the iterate tag!).
    Besides the fields needed to manage the SubscriptionForm data,
    the object also maintains a runtime link to its own user object.
</p>

<p>
    To create a new subscription,
    SubscriptionAction.java simply creates a new subscription object,
    and sets its user to the object found in the request,
    and then forwards control to its input form, Subscription.jsp.
</p>

<h3><a name="subcription.jsp" id="subcription.jsp">Subscription.jsp</a></h3>

<p>
    Saving the best for last, Subscription.jsp utilizes two interesting Struts
    custom form tags,
    "html:options" and "html:checkbox".

<p>
    In Registration.jsp, the Struts iteration tag was used to write a list of
    subscriptions.
    Another place where iterations and collections are handy is the option
    list for a HTML select tag.
    Since this is such a common situation, Struts offers a html:options
    (plural) tag
    that can take an array of objects as a parameter.
    The tag then iterates over the members of the array (beans) to place each
    one inside an standard option tag.
    So given a block like</p>

<pre><code>&lt;html:select property="type"&gt;
    &lt;html:options
    collection="serverTypes"
    property="value"
    labelProperty="label" /&gt;
    &lt;/html:select&gt;</code></pre>

<p>The tag outputs a block like</p>

<pre><code>&lt;select name="type"&gt;
    &lt;option value="imap" selected&gt;IMAP Protocol&lt;/option&gt;
    &lt;option value="pop3"&gt;POP3 Protocol&lt;/option&gt;
    &lt;/select&gt;</code></pre>

<p>
    Here, one collection contained both the labels and the values, from
    properties of the same name.
    Options can also use a second array for the labels, if they do not match
    the values.
    Options can use a Collection, Iterator, or Map for the source of the list.
</p>

<p>
    Unlike other data, the serverTypes array is not fetched from the database.
    Instead, it is loaded by a Struts plugin.
    The <strong>DigestingPlugin</strong> parses an XML document using a given
    set of Digester rules.
    The MailReader uses a set of rules for "LabelValueBeans" to create a list
    of server types.
</p>

<hr/>
<h5>Tip:</h5>
<blockquote>
    <p><font class="hint">
        <strong>LabelValueBeans</strong> -
        Many developers find the LabelValueBeans useful,
        so the class is available in the Struts Action distribution as
        [org.apache.struts.util.LabelValueBean].
    </font></p>
</blockquote>
<hr/>

<p>
    The plugin stores the list is stored in application scope.
    Since the Struts custom tags, like standard JSP tags, search the scopes in
    succession,
    the tag finds the list in application scope and uses it to write out the
    options.
</p>


<h4><a name="SubscriptionForm.java" id="SubscriptionForm.java">SubscriptionForm.java</a>
</h4>

<p>
    Back in Subscription.jsp, we have one more block to cover.
    Although the same basic form can be used to created, edit, or delete a
    subscription,
    people might expect the buttons to be labeled differently in each case.
    Like the Registration page, the Subscription page handles customization
    by using a logic tag to output a different set of buttons for each case.
    Changing buttons doesn't really change the way the Subscription page
    works,
    but customizing the buttons does make things less confusing for the user.
</p>

<pre><code>&lt;logic:equal
    name="SubscriptionForm"
    <strong>property="task"</strong>
    scope="request"
    value="Create"&gt;
    &lt;html:submit&gt;
    <b>&lt;bean:message key="button.save"/&gt;<br/></b> &lt;/html:submit&gt;
    &lt;/logic:equal&gt;</code></pre>

<p>
    In the case of a request to delete a subscription,
    the submit button is labeled "Confirm", since this view is meant to give
    the user a last chance to cancel,
    before sending that task along to SaveSubscriptionAction.java.
</p>

<p>
    The actual task property is placed into the form as a hidden field,
    and SaveSubscriptionAction uses that property to execute the appropriate
    task.
</p>

<h4><a name="SubscriptionAction.java" id="SubscriptionAction.java">SubscriptionAction.java</a>
</h4>

<p>
    Our final stop has the job of finishing what SubscriptionAction.Edit
    started.
    After the usual logic and error checking,
    The SubscriptionAction.Save method either deletes or updates
    the subscription object being handled by this request,
    and cleans up the bean, just to be tidy.
    By now, you should be very comfortable reading through the source on your
    own, to pickup the finer points.
</p>

<hr/>
<h5>SubscriptionAction.Save</h5>
<pre><code> public ActionForward <strong>Save</strong>(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response)
    throws Exception {

    final String method = Constants.SAVE;
    doLogProcess(mapping,method);

    User user = doGetUser(request);
    if (user == null) {
    return doFindLogon(mapping);
    }

    HttpSession session = request.getSession();
    if (isCancelled(request)) {
    <strong>doCancel</strong>(session,method,Constants.SUBSCRIPTION_KEY);
    return doFindSuccess(mapping);
    }

    String action = doGet(form,TASK);
    Subscription subscription = <strong>doGetSubscription</strong>(request);
    boolean isDelete = action.equals(Constants.DELETE);
    if (isDelete) {
    return <strong>doRemoveSubscription</strong>
    (mapping,session,user,subscription);
    }

    if (subscription==null) {
    subscription = <strong>user.createSubscription</strong>(doGet(form,HOST));
    session.setAttribute(Constants.SUBSCRIPTION_KEY,subscription);
    }

    doPopulate(subscription,form);
    <strong>doSaveUser</strong>(user);
    session.removeAttribute(Constants.SUBSCRIPTION_KEY);

    return doFindSuccess(mapping);
    }</code></pre>
<hr/>

<p>
    This concludes our tour.
    To review, you may wish to trace the path a new user takes
    when they register with the application for the first time.
    You should also read over each of the .java and JSP files carefully,
    since we only covered the high points here.
</p>

<h3><a name="Review" id="Review">Review</a></h3>

<ul>
    <li>Struts uses a single controller servlet to route HTTP requests.</li>

    <li>The requests are routed to action objects according to path (or
        URI).</li>

    <li>Each request is handled as a separate thread</li>

    <li>There is only one object for each action (URI), so your action objects
        must be multi-thread safe.</li>

    <li>The configuration of action objects are loaded from a XML resource
        file, rather than hardcoded.</li>

    <li>Action objects can respond to the request, or ask the controller to
        forward the request to another object or to another page, such as an
        input form.</li>

    <li>A library of custom tags works with the rest of the framework to
        enhance use of JavaServer Pages.</li>

    <li>The Struts form tag can work closely with an action objects via a
        Struts ActionFormBean to retain the state of a data-entry form, and
        validate the data entered.</li>

    <li>ActionForm beans can be automatically created by the JSP form or
        controller servlet.</li>

    <li>Struts supports a message resource for loading constants strings.
        Alternate message resources can be provided to internationalize an
        application.</li>
</ul>
<hr/>
</blockquote>
</body>
</html>
